using System;
using System.Threading;

namespace Cmpp.Client.Cmpp3Message.Utility {
    public class CmppMessageReader {
        private const int INT32_BYTE_LENGTH = 4;
        private const int INT64_BYTE_LENGTH = 8;
        private readonly byte[] m_data;
        private int m_postion;

        public CmppMessageReader(byte[] data) {
            if (data == null) {
                m_data = new byte[0];
            }
            else {
                m_data = data;
            }

            m_postion = 0;
        }

        public void Reset() {
            m_postion = 0;
        }

        public bool EOF {
            get {
                if (m_data.Length <= m_postion) {
                    return false;
                }

                if (m_data.Length == 0) {
                    return true;
                }

                return false;
            }
        }

        public ulong ReadUInt64() {
            if (!CanRead(INT64_BYTE_LENGTH)) {
                throw new InvalidOperationException();
            }

            byte[] bytes = ReadBytes(INT64_BYTE_LENGTH);
            ulong result = DataConvert.BytesToUInt32(bytes);

            return result;
        }

        public uint ReadUInt32() {
            if (!CanRead(INT32_BYTE_LENGTH)) {
                throw new InvalidOperationException();
            }

            byte[] bytes = ReadBytes(INT32_BYTE_LENGTH);
            uint result = DataConvert.BytesToUInt32(bytes);

            return result;
        }

        public byte ReadByte() {
            if (!CanRead(1)) {
                throw new InvalidOperationException();
            }

            byte result = m_data[m_postion];

            Interlocked.Increment(ref m_postion);
            return result;
        }

        public byte[] ReadBytes(int count) {
            if (!CanRead(count)) {
                throw new InvalidOperationException();
            }

            byte[] result = new byte[count];
            Buffer.BlockCopy(m_data, m_postion, result, 0, count);

            Interlocked.Add(ref m_postion, count);

            return result;
        }

        public string ReadString(int count) {
            if (!CanRead(count)) {
                throw new InvalidOperationException();
            }

            byte[] bytes = ReadBytes(count);
            return GlobalSettings.DefaultEncoding.GetString(bytes).Trim('\0');
        }

        public bool CanRead(int count) {
            if (m_data.Length < m_postion + count) {
                return false;
            }

            return true;
        }

        public byte[] GetBytes() {
            return m_data;
        }
    }
}